package resoft.jeasyform.impl;

import resoft.jeasyform.core.LayoutReader;
import resoft.jeasyform.core.MenuLoader;
import resoft.jeasyform.components.*;
import resoft.jeasyform.util.ClassUtil;
import resoft.jeasyform.util.EnvUtil;
import resoft.jeasyform.event.EventHandler;
import resoft.jeasyform.event.PreventEmptyEventHandler;
import resoft.jeasyform.event.MinLengthEventHandler;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;

/**
 * <p></p>
 * User: albert
 * Date: Aug 27, 2007
 * Time: 1:17:48 AM
 */
public class XmlLayoutReader implements LayoutReader {
    private static final Log logger = LogFactory.getLog(XmlLayoutReader.class);

    private static final SAXParserFactory parserFactory = SAXParserFactory.newInstance();

    /**
     * get window layout by name
     *
     * @param winName String window's name
     */
    public Window getWindow(String winName) {
        String jformHome = EnvUtil.getJFormHome();

        try {
            SAXParser parser = parserFactory.newSAXParser();
            Window win = new Window();
            String path = jformHome + "etc/" + winName + ".xml";
            logger.info("loading screen definition:" + path);
            parser.parse(new File(path), new XmlWindowParserHandler(win));
            return win;
        } catch (Exception e) {
            logger.error("new SAXParser error", e);
            return null;
        }
    }
}

class XmlWindowParserHandler extends DefaultHandler {
    XmlWindowParserHandler(Window win) {
        this.win = win;
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.equalsIgnoreCase("window")) {
            processWindowTag(attributes);
        } else if (qName.equalsIgnoreCase("property")) {
            processPropertyTag(attributes);
        } else if (qName.equalsIgnoreCase("label")) {
            processLabelTag(attributes);
        } else if (qName.equalsIgnoreCase("input")) {
            processInputTag(attributes);
        } else if (qName.equalsIgnoreCase("button")) {
            processButtonTag(attributes);
        } else if (qName.equalsIgnoreCase("statusBar")) {
            processStatusBarTag(attributes);
        } else if (qName.equalsIgnoreCase("rectangle")) {
            processRectangleTag(attributes);
        } else if (qName.equalsIgnoreCase("menu")) {
            processMenuTag(attributes);
        } else if (qName.equalsIgnoreCase("item")) {
            processMenuItemTag(attributes);
        }
    }




    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equals("menu")) {
            MenuLoader menuLoader = new DefaultMenuLoader();
            menuLoader.loadMenu(win,menu);
        }
    }

    private void processMenuItemTag(Attributes attributes) {
        String text = attributes.getValue("text");
        String id = attributes.getValue("id");
        String clicked = attributes.getValue("clicked");
        MenuItem menuItem = new MenuItem();
        menuItem.setId(Integer.parseInt(id));
        menuItem.setText(text);
        menuItem.setClickedEvent(clicked);
        menu.getRootMenuItem().addChild(menuItem);
    }

    private void processMenuTag(Attributes attributes) {
        String x = attributes.getValue("x");
        if(x!=null && !x.equals("")) {
            menu.setX(Integer.parseInt(x));
        }
        String y = attributes.getValue("y");
        if(y!=null && !y.equals("")) {
            menu.setY(Integer.parseInt(y));
        }
    }

    private void processRectangleTag(Attributes attributes) {
        Rectangle rectangle = new Rectangle();
        setComponentAttributes(rectangle, attributes);
        win.add(rectangle);
    }

    private void processStatusBarTag(Attributes attributes) {
        String title = attributes.getValue("title");
        String text = attributes.getValue("message");
        win.setupStatusBar(title, text);
    }

    private void processButtonTag(Attributes attributes) {
        String text = attributes.getValue("text");
        Button button = new Button(text);
        String clickedEvent = attributes.getValue("clicked");
        button.registerClickedEvent((EventHandler) ClassUtil.newInstance(clickedEvent));
        setComponentAttributes(button, attributes);
        win.add(button);
    }

    private void processInputTag(Attributes attributes) {
        String type = attributes.getValue("type");
        if (type.equalsIgnoreCase("text") || type.equalsIgnoreCase("password")) {
            InputField inputField = null;
            if (type.equalsIgnoreCase("text")) {
                inputField = new TextField();
                //validation
                ((TextField) inputField).setValidation(attributes.getValue("validation"));
            } else if (type.equalsIgnoreCase("password")) {
                inputField = new PasswordField();
            }
            if (inputField != null) {
                //setComponentAttributes must be head of value.cos TextFieldUtil.setValue
                String maxLength = attributes.getValue("maxLength");
                if (maxLength != null && !maxLength.equals("")) {
                    inputField.setMaxLength(Integer.parseInt(maxLength));
                }

                inputField.setValue(attributes.getValue("value"));
                setComponentAttributes(inputField, attributes);

                //empty
                String empty = attributes.getValue("empty");
                if ("no".equalsIgnoreCase(empty) || "false".equalsIgnoreCase(empty)) {
                    inputField.registerPostEvent(new PreventEmptyEventHandler());
                }
                //minLength
                String minLength = attributes.getValue("minLength");
                if (minLength != null) {
                    inputField.registerPostEvent(new MinLengthEventHandler(Integer.parseInt(minLength)));
                }

                String postEvent = attributes.getValue("postEvent");
                inputField.registerPostEvent((EventHandler) ClassUtil.newInstance(postEvent));
                win.add(inputField);
            }

        } else if (type.equalsIgnoreCase("select")) {
            SelectionField selectField = new SelectionField();
            selectField.setOptions(attributes.getValue("options"));
            setComponentAttributes(selectField, attributes);
            win.add(selectField);
        }
    }

    private void processLabelTag(Attributes attributes) {
        String text = attributes.getValue("text");
        Label label = new Label(text);
        setComponentAttributes(label, attributes);
        win.add(label);
    }

    private void processPropertyTag(Attributes attributes) {
        String name = attributes.getValue("name");
        String value = attributes.getValue("value");
        win.setProperty(name, value);
    }


    /**
     * process window tag
     *
     * @param attributes Attributes
     * */
    private void processWindowTag(Attributes attributes) {
        String initEvent = attributes.getValue("init");
        win.registerInitEvent((EventHandler) ClassUtil.newInstance(initEvent));
    }




    private void setComponentAttributes(Component component, Attributes attributes) {
        String x = attributes.getValue("x");
        component.setX(Integer.parseInt(x));
        component.setY(Integer.parseInt(attributes.getValue("y")));
        component.setWidth(Integer.parseInt(attributes.getValue("width")));
        String height = attributes.getValue("height");
        if (height != null && !height.equals("")) {
            component.setHeight(Integer.parseInt(height));
        }
        component.setAlign(attributes.getValue("align"));
        String name = attributes.getValue("name");
        if (name == null) {
            name = "";
        }
        component.setName(name);
    }

    private Window win;
    private Menu menu = new Menu();
}
